package com.demo.spring.cloud.gateway.filter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 运行时间过滤器
 * 定义局部过滤器，只能在一个分组 或者一个路由当中使用
 * @author wangzhilong
 * @date 2019-06-14
 */
public class ElapsedTimeFilter implements GatewayFilter, Ordered {

    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";


    /**
     * 我们在请求刚刚到达时，往ServerWebExchange中放入了一个属性elapsedTimeBegin，属性值为当时的毫秒级时间戳。然后在请求执行结束后，
     * 又从中取出我们之前放进去的那个时间戳，与当前时间的差值即为该请求的耗时。因为这是与业务无关的日志所以将Ordered设为Integer.MAX_VALUE以降低优先级。
     * 现在再来看我们之前的问题：怎么来区分是 “pre” 还是 “post” 呢？其实就是chain.filter(exchange)之前的就是 “pre” 部分，之后的也就是then里边的是 “post” 部分。
     *
     * 实际在使用 Spring Cloud 的过程中，我们会使用 Sleuth+Zipkin 来进行耗时分析。
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() ->{
                    Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
                    if (startTime != null) {
                        log.info(exchange.getRequest().getURI().getRawPath() +":" + (System.currentTimeMillis() -startTime) + "ms");
                    }
                })
        );
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}
